package cn.frontop.funswitch.util;

import cn.frontop.funswitch.common.CommonConstant;
import cn.frontop.funswitch.common.Result;
import cn.frontop.funswitch.config.webSocket.WebSocket;
import cn.frontop.funswitch.entity.ApiPathEntity;
import cn.frontop.funswitch.entity.DatasourceEntity;
import cn.frontop.funswitch.entity.SocketConfigEntity;
import cn.frontop.funswitch.entity.SqlScriptEntity;
import cn.frontop.funswitch.exception.FunSwitchException;
import cn.frontop.funswitch.service.DatasourceService;
import cn.frontop.funswitch.service.IndexConfigService;
import cn.frontop.funswitch.service.SocketConfigService;
import cn.frontop.funswitch.service.SqlScriptService;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Yun
 */
@Slf4j
public class CommonUtil {

    /**
     * 获取实体列表（分页）
     *
     * @param service  某实体对应的service类
     * @param pageNo   当前页码
     * @param pageSize 每页显示条数
     * @return 某实体的分页结果集
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static Result<?> entityPageList(IService<?> service, Integer pageNo, Integer pageSize) {
        return Result.ok(service.page(new Page(pageNo, pageSize)));

    }

    /**
     * 获取实体列表（分页）
     *
     * @param service      某实体对应的service类
     * @param pageNo       当前页码
     * @param pageSize     每页显示条数
     * @param queryWrapper 参数
     * @return 某实体的分页结果集
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static Result<?> entityPageList(IService<?> service, Integer pageNo, Integer pageSize, AbstractWrapper queryWrapper) {
        return Result.ok(service.page(new Page(pageNo, pageSize), queryWrapper));
    }

    /**
     * 内存连表分页（分页）
     *
     * @param service      某实体对应的service类
     * @param pageNo       当前页码
     * @param pageSize     每页显示条数
     * @param queryWrapper 参数
     * @return 某实体的分页结果集
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static Result<?> entityPageList(IService<?> service, Integer pageNo, Integer pageSize, AbstractWrapper queryWrapper, Function function) {
        Page<Object> page = service.page(new Page(pageNo, pageSize), queryWrapper);
        page.setRecords((List<Object>) function.apply(page.getRecords()));
        return Result.ok(page);
    }

    /**
     * 从请求获取请求参数
     *
     * @param request
     * @return
     */
    public static JSONObject getHttpJsonBody(HttpServletRequest request) {
        try {
            InputStreamReader in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(in);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            return JSONUtil.isTypeJSON(sb.toString()) ? JSONUtil.parseObj(sb.toString()) : new JSONObject();
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 从请求获取请求参数
     */
    public static JSONArray getHttpJsonBodyToArray(HttpServletRequest request) {
        try {
            InputStreamReader in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(in);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            return JSONUtil.isTypeJSON(sb.toString()) ? toJsonArray(sb.toString()) : new JSONArray();
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 提取方法 统一
     * 空则 抛出异常上游处理  打断流程
     *
     * @param obj 对象
     * @param msg 失败信息
     */
    public static void isEmpty(Object obj, String msg) {
        if (obj == null || ArrayUtil.isEmpty(obj) || StrUtil.isEmptyIfStr(obj)) {
            throw new FunSwitchException(msg);
        }
    }

    /**
     * 追加方法
     *
     * @param source 源数据
     * @param target 目标数据
     * @return 都有返回合并结果, 没有返回有的
     */
    public static String apply(String source, String target) {
        //都空
        if (StrUtil.isEmpty(source) && StrUtil.isEmpty(target)) {
            return "{}";
        }
        if (StrUtil.isEmpty(source)) {
            return target;
        } else if (StrUtil.isEmpty(target)) {
            return source;
        } else {
            JSONObject jsonObject = JSONUtil.parseObj(target);
            jsonObject.putAll(JSONUtil.parseObj(source));
            return JSONUtil.toJsonStr(jsonObject);
        }
    }

    /**
     * 追加方法
     *
     * @param source 源数据
     * @param target 目标数据
     * @param add    添加数据
     * @return 都有返回合并结果, 没有返回有的
     */
    public static String apply(String source, String target, Map<String, Object> add) {
        //都空
        if (StrUtil.isEmpty(source) && StrUtil.isEmpty(target)) {
            return JSONUtil.toJsonStr(add);
        }
        if (StrUtil.isEmpty(source)) {
            JSONObject jsonObject = JSONUtil.parseObj(target);
            jsonObject.putAll(add);
            return JSONUtil.toJsonStr(jsonObject);
        } else if (StrUtil.isEmpty(target)) {
            JSONObject jsonObject = JSONUtil.parseObj(source);
            jsonObject.putAll(add);
            return JSONUtil.toJsonStr(jsonObject);
        } else {
            JSONObject jsonObject = JSONUtil.parseObj(target);
            jsonObject.putAll(JSONUtil.parseObj(source));
            jsonObject.putAll(add);
            return JSONUtil.toJsonStr(jsonObject);
        }
    }

    /**
     * 统一格式 避免重复造轮子
     *
     * @param json json
     * @return jsonArray
     */
    public static JSONArray toJsonArray(String json) {
        JSONArray result = new JSONArray();
        if (!JSONUtil.isTypeJSON(json)) {
            throw new FunSwitchException("不是JSON格式解析失败!!!");
        } else if (JSONUtil.isTypeJSONObject(json)) {
            result.add(JSONUtil.parseObj(json));
        } else {
            result = JSONUtil.parseArray(json);
        }
        return result;
    }

    /**
     * 处理过程
     *
     * @param apiPathEntity      api实体类
     * @param request            请求
     * @param indexConfigService 指标服务
     * @return
     */
    public static Result<Object> process(ApiPathEntity apiPathEntity, HttpServletRequest request, IndexConfigService indexConfigService) {
        CommonUtil.isEmpty(apiPathEntity, "该路径不存在!!!");
        //结果
        Object result = null;
        //0.普通接口1.混合请求接口(叠加)2.混合请求接口(主键),3.SQL接口 4.静态接口5.回调接口 6.二次开发
        switch (apiPathEntity.getType()) {
            case 0:
                result = indexConfigService.getIndex(Integer.parseInt(apiPathEntity.getIndexId()), CommonUtil.getHttpJsonBody(request));
                break;
            case 1:
                List<Object> collect = JSONUtil.parseArray(apiPathEntity.getIndexId()).stream().map(t -> indexConfigService.getIndex(Integer.parseInt(t.toString()), CommonUtil.getHttpJsonBody(request))).collect(Collectors.toList());
                result = fusion(collect.get(0), collect.get(1));
                break;
            case 2:
                result = fusionByPrimaryKey(apiPathEntity.getPrimaryKey(), JSONUtil.parseArray(apiPathEntity.getIndexId()).stream().map(t -> indexConfigService.getIndex(Integer.parseInt(t.toString()), CommonUtil.getHttpJsonBody(request))).collect(Collectors.toList()));
                break;
            case 3:
                SqlScriptService sqlScriptService = SpringUtil.getBean(SqlScriptService.class);
                SqlScriptEntity sqlScriptEntity = sqlScriptService.getById(JSONUtil.isTypeJSONArray(apiPathEntity.getIndexId()) ? JSONUtil.parseArray(apiPathEntity.getIndexId()).getInt(0) : apiPathEntity.getIndexId());
                CommonUtil.isEmpty(sqlScriptEntity, "不存在该SQL脚本!");
                DatasourceService datasourceService = SpringUtil.getBean(DatasourceService.class);
                DatasourceEntity datasourceEntity = datasourceService.getById(sqlScriptEntity.getSourceId());
                CommonUtil.isEmpty(sqlScriptEntity, "数据源不存在!");
                result = SqlUtil.execute(datasourceEntity, sqlScriptEntity.getScript());
                break;
            case 4:
                result = CommonUtil.isJson(apiPathEntity.getStaticData());
                break;
            case 5:
                Object callBack = indexConfigService.callBack(JSONUtil.isTypeJSONArray(apiPathEntity.getIndexId()) ? JSONUtil.parseArray(apiPathEntity.getIndexId()).getInt(0) : Integer.parseInt(apiPathEntity.getIndexId()), getHttpJsonBody(request));
                SocketConfigService socketConfigService = SpringUtil.getBean(SocketConfigService.class);
                SocketConfigEntity socketConfigEntity = socketConfigService.getBaseMapper().selectOne(new QueryWrapper<SocketConfigEntity>().lambda().eq(SocketConfigEntity::getSourceId, apiPathEntity.getId()).eq(SocketConfigEntity::getType, 1).eq(SocketConfigEntity::getStatus, true));
                CommonUtil.isEmpty(socketConfigEntity, "配置错误,Socket配置不存在!");
                WebSocket.sendMessage(JSONUtil.toJsonStr(callBack), CommonConstant.SOCKET + socketConfigEntity.getPath());
                break;
            default:
                return Result.ok("不存在该类型!!!");
        }
        return Result.ok(result);
    }

    /**
     * 测试过程
     *
     * @param apiPathEntity      api实体类
     * @param request            请求
     * @param indexConfigService 指标服务
     * @return
     */
    public static Object testProcess(ApiPathEntity apiPathEntity, JSONObject request, IndexConfigService indexConfigService) {
        CommonUtil.isEmpty(apiPathEntity, "该路径不存在!!!");
        //结果
        Object result = null;
        //0.普通接口1.混合请求接口(叠加)2.混合请求接口(主键),3.SQL接口 4.静态接口
        switch (apiPathEntity.getType()) {
            case 0:
                result = indexConfigService.getIndex(Integer.parseInt(apiPathEntity.getIndexId()), request);
                break;
            case 1:
                List<Object> collect = JSONUtil.parseArray(apiPathEntity.getIndexId()).stream().map(t -> indexConfigService.getIndex(Integer.parseInt(t.toString()), request)).collect(Collectors.toList());
                result = fusion(collect.get(0), collect.get(1));
                break;
            case 2:
                result = fusionByPrimaryKey(apiPathEntity.getPrimaryKey(), JSONUtil.parseArray(apiPathEntity.getIndexId()).stream().map(t -> indexConfigService.getIndex(Integer.parseInt(t.toString()), request)).collect(Collectors.toList()));
                break;
            case 3:
                SqlScriptService sqlScriptService = SpringUtil.getBean(SqlScriptService.class);
                SqlScriptEntity sqlScriptEntity = sqlScriptService.getById(JSONUtil.isTypeJSONArray(apiPathEntity.getIndexId()) ? JSONUtil.parseArray(apiPathEntity.getIndexId()).getInt(0) : apiPathEntity.getIndexId());
                CommonUtil.isEmpty(sqlScriptEntity, "不存在该SQL脚本!");
                DatasourceService datasourceService = SpringUtil.getBean(DatasourceService.class);
                DatasourceEntity datasourceEntity = datasourceService.getById(sqlScriptEntity.getSourceId());
                CommonUtil.isEmpty(sqlScriptEntity, "数据源不存在!");
                result = SqlUtil.execute(datasourceEntity, sqlScriptEntity.getScript());
                break;
            case 4:
                result = CommonUtil.isJson(apiPathEntity.getStaticData());
                break;
            default:
                throw new FunSwitchException("不存在该类型或该类型不可测试!!!");
        }
        return result;
    }

    /**
     * 融合模式 主键
     *
     * @param primaryKey 主键
     * @param list       数据
     * @return 结果
     */
    @SuppressWarnings("Convert2MethodRef")
    private static Object fusionByPrimaryKey(String primaryKey, List<Object> list) {
        ArrayList<JSONObject> jsonObjects = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i) instanceof Map) {
                jsonObjects.add(JSONUtil.parseObj(list.get(i)));
            } else if (list.get(i) instanceof List) {
                jsonObjects.addAll(JSONUtil.parseArray(list.get(i)).stream().map(JSONObject::new).collect(Collectors.toList()));
            }
        }
        Map<Object, List<JSONObject>> collect = jsonObjects.stream().collect(Collectors.groupingBy(t -> t.get(primaryKey)));
        return collect.keySet().stream().map(t -> {
            HashMap<String, Object> hashMap = new HashMap<>();
            collect.get(t).forEach(t1 -> hashMap.putAll(t1));
            return hashMap;
        }).collect(Collectors.toList());
    }

    /**
     * 融合
     * 没有匹配 符合的匹配条件时 返回 @source
     *
     * @param source 源
     * @param target 目标
     * @return 结果
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private static Object fusion(Object source, Object target) {
        ArrayList<Map> maps = new ArrayList<>();
        if (source instanceof List && target instanceof List) {
            List temp = (List) source;
            List temp1 = (List) target;
            for (int i = 0; i < Math.min(temp.size(), temp1.size()); i++) {
                Map map = (Map) temp.get(i);
                map.putAll(((Map) temp1.get(i)));
                maps.add(map);
            }
        } else if (source instanceof Map && target instanceof Map) {
            Map temp = (Map) source;
            temp.putAll((Map) target);
            maps.add(temp);
        } else if (source instanceof Map && target instanceof List) {
            Map temp = (Map) source;
            List temp1 = (List) target;
            temp.putAll((Map) temp1.get(0));
            for (int i = 1; i < temp1.size(); i++) {
                maps.add((Map) temp1.get(i));
            }
            maps.add(temp);
        } else if (source instanceof List && target instanceof Map) {
            List temp = (List) source;
            Map temp1 = (Map) target;
            temp1.putAll((Map) temp.get(0));
            for (int i = 1; i < temp.size(); i++) {
                maps.add((Map) temp.get(i));
            }
            maps.add(temp1);
        } else {
            return source;
        }
        return maps;
    }


    /**
     * 判断是否为json
     *
     * @param json json字符串
     * @return 对象
     */
    public static Object isJson(String json) {
        return JSONUtil.isTypeJSON(json) ? JSONUtil.parse(json) : json;
    }
}
